<?php

namespace App\Service\Cruise\Mission;

use App\Enums\BaseErrorCode;
use App\Enums\OpenShop\InvestmentPromotion\UserContractEnum;
use App\Enums\Workflow\WorkflowEnum;
use App\Exceptions\Custom\ResponseHttpException;
use App\Models\Cruise\CruiseOrderModel;
use App\Models\Cruise\CruiseTaskProjectModel;
use App\Models\Cruise\CruiseTemplateModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopMainProcessModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopUserBaseInfoModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopUserContractModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopUserIdentityCardModel;
use App\Models\Workflow\WorkflowOrderLogModel;
use App\Models\Workflow\WorkflowOrderNodeModel;
use App\Remote\Rms\RmsUserRemote;
use App\Service\BaseService;
use App\Service\Renew\RenewOrderService;
use App\Service\Renew\RenewService;
use App\Support\CustomForm\AttributeCruiseSupport;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Kuafu\File\FileUtil;
use Kuafu\File\PrivateFileUtil;

class RenewInputService extends CruiseOrderInputBaseService
{
    private ?CruiseOrderModel $cruiseOrderModel;
    protected int               $userId;
    private array             $currentHandlerInfo = [];

    public function __construct(int $cruiseOrderId, int $userId = 0)
    {
        $this->userId = $userId;

        if ($cruiseOrderId) {
            $this->cruiseOrderModel = CruiseOrderModel::query()->where('id', $cruiseOrderId)->first();
            if (!$this->cruiseOrderModel) {
                throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null,
                    "不存在的续签任务ID:{$cruiseOrderId}");
            }

            $this->pConstruct();
        }
    }

    private function pConstruct()
    {
        parent::__construct($this->cruiseOrderModel->id, $this->cruiseOrderModel->type,
            CruiseTemplateModel::SYS_TEMPLATE_WORKFLOW_RENEW);
    }

    public function getCruiseOrderModel(): ?CruiseOrderModel
    {
        return $this->cruiseOrderModel;
    }

    /**
     * 初始化cruise_orders
     * @param int $shopId
     * @param int $templateId
     * @return $this
     */
    public function initCruiseOrder(int $shopId, int $templateId): self
    {
        // 查询最新的单子
        $mainProcess    = OpenShopMainProcessModel::query()->where('shopId', $shopId)->orderByDesc('id')->first();
        $merchantUserId = (int)optional($mainProcess->signOrderRel)->merchantUserId;

        // 创建cruise_order
        $this->cruiseOrderModel = CruiseOrderModel::query()->create([
            'orderNo'    => $mainProcess->orderNo,
            'type'       => CruiseTemplateModel::TYPE_7,
            'status'     => CruiseOrderModel::STATUS_NOT_SUBMIT,
            'shopId'     => $shopId,
            'templateId' => $templateId,
            'handlerId'  => $merchantUserId,
        ]);

        $this->pConstruct();

        return $this;
    }

    /**
     * 初始化表单信息
     * @return void
     */
    public function initOrderInput(): void
    {
        $cruiseOrderInputModel = parent::baseInitOrderInput($this->cruiseOrderModel->templateId);

        // 合同中的用户信息
        $contractUserInfo = (new RenewService($this->cruiseOrderModel->shopId))->userInfo();
        if ($contractUserInfo) {

            $userContentJson    = json_decode($cruiseOrderInputModel->userContentJson, true);
            $inputObjectJsonArr = $cruiseOrderInputModel->inputObjectJsonArr;

            foreach ($cruiseOrderInputModel->inputObjectJsonArr as $k1 => $positions) {
                foreach ($positions['projects'] as $k2 => $project) {
                    $projectObj = unserialize($project);

                    $meanType = $projectObj->meanType;
                    $field    = $projectObj->inputName;

                    switch ($meanType) {
                        case CruiseTaskProjectModel::MEAN_TYPE_NAME:
                            $userContentJson[$field] = $contractUserInfo['name'];
                            $projectObj->setCustomAttribute(['disabled', true]);
                            break;
                        case CruiseTaskProjectModel::MEAN_TYPE_PHONE:
                            $userContentJson[$field] = $contractUserInfo['phone'];
                            $projectObj->setCustomAttribute(['disabled', true]);
                            break;
                        case CruiseTaskProjectModel::MEAN_TYPE_ID_CARD:
                            $userContentJson[$field] = $contractUserInfo['idCard'];
                            $projectObj->setCustomAttribute(['disabled', true]);
                            break;
                        case CruiseTaskProjectModel::MEAN_TYPE_ID_CARD_FRONT:

                            if ($contractUserInfo['frontSideImg']) {

                                // 上传并转成公有的
                                $url                     = $this->convertPrivateToPublic($contractUserInfo['frontSideImg']);
                                $userContentJson[$field] = ['url' => $url];
                                $projectObj->setCustomAttribute(['disabled', true]);
                            }

                            break;
                        case CruiseTaskProjectModel::MEAN_TYPE_ID_CARD_BACK:

                            if ($contractUserInfo['backSideImg']) {

                                // 上传并转成公有的
                                $url                     = $this->convertPrivateToPublic($contractUserInfo['backSideImg']);
                                $userContentJson[$field] = ['url' => $url];
                                $projectObj->setCustomAttribute(['disabled', true]);
                            }
                            break;
                        case CruiseTaskProjectModel::MEAN_TYPE_EMAIL:
                            $userContentJson[$field] = $contractUserInfo['email'];
                            break;
                        case CruiseTaskProjectModel::MEAN_TYPE_WECHAT:
                            $userContentJson[$field] = $contractUserInfo['wechat'];
                            break;
                        case CruiseTaskProjectModel::MEAN_TYPE_ADDRESS:
                            $userContentJson[$field] = $contractUserInfo['addressDetail'];
                            break;
                        case CruiseTaskProjectModel::MEAN_TYPE_PROVINCE_CITY_AREA:
                            $userContentJson[$field] = $contractUserInfo['addressPrefixArr'];
                            break;
                        case CruiseTaskProjectModel::MEAN_TYPE_BANK_CARD_NO:
                            $userContentJson[$field] = $contractUserInfo['cardNo'];
                            break;
                        case CruiseTaskProjectModel::MEAN_TYPE_BANK_CARD_OPENING_BANK:
                            $userContentJson[$field] = $contractUserInfo['cardBankName'];
                            break;
                        case CruiseTaskProjectModel::MEAN_TYPE_BANK_CARD_USER_NAME:
                            $userContentJson[$field] = $contractUserInfo['cardAccountName'];
                            break;
                    }

                    $inputObjectJsonArr[$k1]['projects'][$k2] = serialize($projectObj);
                }
            }

            $cruiseOrderInputModel->userContentJson = json_encode($userContentJson);
            $cruiseOrderInputModel->inputObjectJson = json_encode($inputObjectJsonArr);
            $cruiseOrderInputModel->save();
        }
    }

    public function saveUserContentJson(string $field, $value, array $auditValue = []): void
    {
        // 判断节点
        parent::baseSaveUserContentJson($field, $value, $auditValue);
    }

    /**
     * 获得表单信息
     * @return array
     */
    public function getInputObjectFill(): array
    {
        $currentHandler = $this->getCurrentHandlerInfo();

        $data           = parent::baseGetInputObjectFill($currentHandler['disable']);
        $data['submit'] = $currentHandler['submit']; // 提交权限
        $data['audit']  = $currentHandler['audit']; // 审核权限
        $data['shopId'] = $this->cruiseOrderModel->shopId;

        // 提交后 - 未填的非必填项。隐藏掉
        if (!in_array($this->cruiseOrderModel->status, [CruiseOrderModel::STATUS_NOT_SUBMIT, CruiseOrderModel::STATUS_NOT_MODIFY])) {

            foreach ($data['lists'] as $k1 => $position) {
                foreach ($position['projects'] as $k2 => $project) {

                    $inputType = $project['inputType'];
                    if ($inputType == AttributeCruiseSupport::INPUT_TYPE_RICH_SHOW) {
                        continue;
                    }

                    $required = true;
                    if (is_array($project['validate'])) {
                        $required = $project['validate']['required'] ?? true;
                    }

                    if (!$required && $project['value'] === null) {
                        unset($data['lists'][$k1]['projects'][$k2]);
                    }
                }

                $data['lists'][$k1]['projects'] = array_values($data['lists'][$k1]['projects']);
            }
        }

        return $data;
    }

    public function submitOrder(): void
    {
        parent::baseSubmitOrder(true);

        $this->setWorkflowOrderNode($this->workflowOrderService->getCurrentMainNode());

        // 提交后干的事

        DB::beginTransaction();

        // 节点状态切换 + 日志更新
        $this->workflowOrderService->finishNodeEnterNext($this->workflowOrderNodeModel->id);

        // cruise_order状态切换
        $this->cruiseOrderModel->status = CruiseOrderModel::STATUS_NOT_REVIEW;
        $this->cruiseOrderModel->save();

        DB::commit();
    }

    public function audit(array $data): void
    {
        // 获取当前节点
        $this->setWorkflowOrderNode($this->workflowOrderService->getCurrentMainNode());

        $auditStatus  = $data['auditStatus'];
        $auditContent = $data['auditContent'];
        $rejectNodeId = $data['rejectNodeId'] ?? 0;

        if ($auditStatus != WorkflowOrderLogModel::AUDIT_NO) {
            $rejectNodeId = 0;
        }

        // 主单
        $mainProcess = OpenShopMainProcessModel::getMainOrder($this->workflowOrderModel->shopId);

        DB::beginTransaction();

        // 节点状态切换 + 日志更新
        $nextNode = $this->workflowOrderService->finishNodeEnterNext($this->workflowOrderNodeModel->id, $auditStatus,
            $auditContent, $rejectNodeId);

        // cruise_order状态切换
        if ($nextNode->businessType == WorkflowEnum::BUSINESS_TYPE_RENEW_SIGN) {
            $this->cruiseOrderModel->status = CruiseOrderModel::STATUS_COMPLETE;
            $this->cruiseOrderModel->save();
        } elseif ($nextNode->businessType == WorkflowEnum::BUSINESS_TYPE_SUBMIT_APPLY) {
            $this->cruiseOrderModel->status = CruiseOrderModel::STATUS_NOT_MODIFY;
            $this->cruiseOrderModel->save();
        }

        DB::commit();

        // 生成续签合同
        if ($nextNode->businessType == WorkflowEnum::BUSINESS_TYPE_RENEW_SIGN) {

            // 审批环节都通过了，同步表单信息至开店信息基础表
            // 同步表单用户信息
            $info                  = $this->getRenewUserBaseInfo();

            OpenShopUserBaseInfoModel::query()->where('orderNo', $mainProcess->orderNo)->update([
                'mobile'          => $info['phone'],
                'wechatNumber'    => $info['wechat'],
                'email'           => $info['email'],
                'address'         => $info['addressDetail'],
                'addressPrefix'   => implode('-', array_column($info['addressPrefixArr'], 'text')),
                'provinceCode'    => $info['addressPrefixArr'][0]['value'] ?? '',
                'cityCode'        => $info['addressPrefixArr'][1]['value'] ?? '',
                'districtCode'    => $info['addressPrefixArr'][2]['value'] ?? '',
                'cardNo'          => $info['cardNo'],
                'cardBankName'    => $info['cardBankName'],
                'cardAccountName' => $info['cardAccountName'],
            ]);

            OpenShopUserIdentityCardModel::query()->where('orderNo', $mainProcess->orderNo)->update([
                'frontSideImg'       => $this->convertPublicToPrivate($info['idCardFront']['url']),
                'backSideImg'        => $this->convertPublicToPrivate($info['idCardBack']['url']),
                'name'               => $info['name'],
                'identityCardNumber' => $info['idCard'],
                'birthday'           => mb_substr($info['idCard'], 6, 8),
                'gender'             => OpenShopUserIdentityCardModel::getCardSex($info['idCard']),
            ]);

            // 生成续签合同
            RenewOrderService::generateRenewUserContract($mainProcess->orderNo, $this->workflowOrderModel->workflowNo);
        }
    }

    /**
     * 续签完成
     * @return void
     */
    public function finish(): void
    {
        Log::info("RenewInputService finish...{$this->workflowOrderModel->workflowNo}");

        // 校验节点状态
        $currentNode = $this->workflowOrderService->getCurrentMainNode();
        if (!$currentNode || $currentNode->businessType != WorkflowEnum::BUSINESS_TYPE_RENEW_SIGN) {
            BaseService::throwErr("当前节点状态不正确");
        }

        DB::beginTransaction();

        // 节点状态切换 + 日志更新
        $this->workflowOrderService->finishNodeEnterNext($currentNode->id);

        DB::commit();
    }

    /**
     * 校验提交权限
     * @return $this
     */
    public function checkSubmit(): self
    {
        if ($this->getCurrentHandlerInfo()['submit']) {
            return $this;
        }

        BaseService::throwErr("没有提交权限，或订单已提交");
    }

    /**
     * 校验审核权限
     * @return $this
     */
    public function checkAudit(): self
    {
        if ($this->getCurrentHandlerInfo()['audit']) {
            return $this;
        }

        BaseService::throwErr("没有审核权限，或已被审核");
    }

    /**
     * 当前处理人信息
     * @return array
     */
    public function getCurrentHandlerInfo(): array
    {
        if ($this->currentHandlerInfo) {
            return $this->currentHandlerInfo;
        }

        // 流程已结束
        if (!$this->workflowOrderService->getCurrentNodes()->count()) {
            return [
                'userIds' => [],
                'submit'  => false,
                'audit'   => false,
                'disable' => true,
            ];
        }

        // 处理人ids
        $handlerUids = $this->workflowOrderService->getCurrentNodes()->map(function (WorkflowOrderNodeModel $item) {
            return $item->handlerUid;
        })->filter()->values()->toArray();

        // 店长权限特殊处理
        if ($this->workflowOrderService->getCurrentNodes()->where('handlerType', WorkflowEnum::HANDLER_TYPE_SHOP_MANAGER)->count()) {
            $manageShopList = array_column(RmsUserRemote::getShopManagerUserByShopId([$this->workflowOrderModel->shopId])['lists'] ?? [], 'userId');
            $handlerUids = array_values(array_unique(array_merge($handlerUids, $manageShopList)));
        }

        // 名字暂时不需要，先不做了
//        $userNames = collect(RmsUserRemote::getRmsUserByIds($handlerUids))->implode('username', ',');

        // 当前主节点
        $currentNode = $this->workflowOrderService->getCurrentMainNode();

        // submit 提交权限
        if ($currentNode->businessType == WorkflowEnum::BUSINESS_TYPE_SUBMIT_APPLY) {
            if (in_array($this->userId, $handlerUids)) {
                $submit  = true;
                $disable = false;
            }
        }

        // audit 审核权限
        if ($currentNode->businessType == WorkflowEnum::BUSINESS_TYPE_FIX_AUDIT) {
            if (in_array($this->userId, $handlerUids)) {
                $audit = true;
            }
        }

        return $this->currentHandlerInfo = [
            'userIds'   => $handlerUids,
//            'userNames' => $userNames,
            'submit'    => $submit ?? false,
            'audit'     => $audit ?? false,
            'disable'   => $disable ?? true,
        ];
    }

    /**
     * 获取续签用户表单填写的基础信息
     * @return array
     */
    public function getRenewUserBaseInfo(): array
    {
        $res = [];

        $lists = $this->getInputObjectFill()['lists'];
        foreach ($lists as $position) {

            foreach ($position['projects'] as $project) {
                switch ($project['meanType'] ?? 0) {
                    case CruiseTaskProjectModel::MEAN_TYPE_PHONE:
                        $res['phone'] = $project['value'];
                        break;
                    case CruiseTaskProjectModel::MEAN_TYPE_EMAIL:
                        $res['email'] = $project['value'];
                        break;
                    case CruiseTaskProjectModel::MEAN_TYPE_WECHAT:
                        $res['wechat'] = $project['value'];
                        break;
                    case CruiseTaskProjectModel::MEAN_TYPE_NAME:
                        $res['name'] = $project['value'];
                        break;
                    case CruiseTaskProjectModel::MEAN_TYPE_ID_CARD:
                        $res['idCard'] = $project['value'];
                        break;
                    case CruiseTaskProjectModel::MEAN_TYPE_ID_CARD_FRONT:
                        $res['idCardFront'] = $project['value'];
                        break;
                    case CruiseTaskProjectModel::MEAN_TYPE_ID_CARD_BACK:
                        $res['idCardBack'] = $project['value'];
                        break;
                    case CruiseTaskProjectModel::MEAN_TYPE_ADDRESS:
                        $res['addressDetail'] = $project['value'];
                        break;
                    case CruiseTaskProjectModel::MEAN_TYPE_PROVINCE_CITY_AREA:
                        $res['addressPrefixArr'] = $project['value'];
                        break;
                    case CruiseTaskProjectModel::MEAN_TYPE_BANK_CARD_NO:
                        $res['cardNo'] = $project['value'];
                        break;
                    case CruiseTaskProjectModel::MEAN_TYPE_BANK_CARD_OPENING_BANK:
                        $res['cardBankName'] = $project['value'];
                        break;
                    case CruiseTaskProjectModel::MEAN_TYPE_BANK_CARD_USER_NAME:
                        $res['cardAccountName'] = $project['value'];
                        break;
                }
            }
        }

        return $res;
    }

    /**
     * 将私有path，转成公有url
     * @param string $path
     * @return string
     * @throws \OSS\Core\OssException
     */
    private function convertPrivateToPublic(string $path): string
    {
        $url       = privateFilePath($path);
        $extension = pathinfo($path, PATHINFO_EXTENSION);
        file_put_contents($localPath = sys_get_temp_dir() . '/' . Str::uuid(), file_get_contents($url));

        // 上传并转成公有的url
        return FileUtil::uploadFile($localPath, $extension)['url'];
    }

    private function convertPublicToPrivate(string $url)
    {
        $extension = pathinfo($url, PATHINFO_EXTENSION);
        file_put_contents($localPath = sys_get_temp_dir() . '/' . Str::uuid(), file_get_contents($url));

        // 将身份证上传私有的
        return PrivateFileUtil::uploadFile($localPath, $extension, generateFileKey())['path'];
    }
}
